using Microsoft.Extensions.Logging;
using Uantek.Device.Communication.Models;
using Uantek.Device.Communication.Protocols.Interfaces;
using Uantek.Device.Communication.Protocols.Modbus;
using Uantek.Device.Communication.Utilities;

namespace Uantek.Device.Communication.Devices
{
    /// <summary>
    /// Modbus设备示例实现
    /// </summary>
    public class ModbusDevice : IDisposable
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger<ModbusDevice>? _logger;

        /// <summary>
        /// 设备协议
        /// </summary>
        private readonly IDeviceProtocol _protocol;

        /// <summary>
        /// 通信传输
        /// </summary>
        private readonly ICommunicationTransport _transport;

        /// <summary>
        /// 设备ID
        /// </summary>
        public string DeviceId { get; }

        /// <summary>
        /// 设备名称
        /// </summary>
        public string DeviceName { get; }

        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected => _transport.IsConnected;

        /// <summary>
        /// 连接信息
        /// </summary>
        public string ConnectionInfo => _transport.ConnectionInfo;

        /// <summary>
        /// 数据接收事件
        /// </summary>
        public event EventHandler<DeviceDataModel>? DataReceived;

        /// <summary>
        /// 连接状态变化事件
        /// </summary>
        public event EventHandler<bool>? ConnectionStatusChanged;

        /// <summary>
        /// 是否已释放
        /// </summary>
        private bool _disposed = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <param name="deviceName">设备名称</param>
        /// <param name="protocol">设备协议</param>
        /// <param name="transport">通信传输</param>
        /// <param name="logger">日志记录器</param>
        public ModbusDevice(string deviceId, string deviceName, IDeviceProtocol protocol, 
            ICommunicationTransport transport, ILogger<ModbusDevice>? logger = null)
        {
            DeviceId = deviceId ?? throw new ArgumentNullException(nameof(deviceId));
            DeviceName = deviceName ?? throw new ArgumentNullException(nameof(deviceName));
            _protocol = protocol ?? throw new ArgumentNullException(nameof(protocol));
            _transport = transport ?? throw new ArgumentNullException(nameof(transport));
            _logger = logger;

            // 订阅传输层事件
            _transport.DataReceived += OnTransportDataReceived;
            _transport.ConnectionStatusChanged += OnTransportConnectionStatusChanged;

            _logger?.LogInformation("Modbus设备实例创建完成，设备ID: {DeviceId}，设备名称: {DeviceName}", DeviceId, DeviceName);
        }

        /// <summary>
        /// 连接设备
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <returns>连接结果</returns>
        public async Task<CommunicationResult> ConnectAsync(Dictionary<string, object> connectionParameters)
        {
            try
            {
                _logger?.LogInformation("开始连接Modbus设备，设备ID: {DeviceId}", DeviceId);

                var result = await _transport.ConnectAsync(connectionParameters);
                
                if (result.Success)
                {
                    _logger?.LogInformation("Modbus设备连接成功，设备ID: {DeviceId}，连接信息: {ConnectionInfo}", 
                        DeviceId, ConnectionInfo);
                }
                else
                {
                    _logger?.LogError("Modbus设备连接失败，设备ID: {DeviceId}，错误: {Message}", DeviceId, result.Message);
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "连接Modbus设备时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult.CreateFailure($"连接设备异常: {ex.Message}", "ConnectionException", ex);
            }
        }

        /// <summary>
        /// 断开设备连接
        /// </summary>
        /// <returns>断开结果</returns>
        public async Task<CommunicationResult> DisconnectAsync()
        {
            try
            {
                _logger?.LogInformation("开始断开Modbus设备连接，设备ID: {DeviceId}", DeviceId);

                var result = await _transport.DisconnectAsync();

                if (result.Success)
                {
                    _logger?.LogInformation("Modbus设备断开连接成功，设备ID: {DeviceId}", DeviceId);
                }
                else
                {
                    _logger?.LogError("Modbus设备断开连接失败，设备ID: {DeviceId}，错误: {Message}", DeviceId, result.Message);
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "断开Modbus设备连接时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult.CreateFailure($"断开设备连接异常: {ex.Message}", "DisconnectionException", ex);
            }
        }

        /// <summary>
        /// 读取线圈状态
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="quantity">数量</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>线圈状态</returns>
        public async Task<CommunicationResult<bool[]>> ReadCoilsAsync(ushort startAddress, ushort quantity, int timeout = 5000)
        {
            try
            {
                _logger?.LogDebug("读取线圈状态，设备ID: {DeviceId}，起始地址: {StartAddress}，数量: {Quantity}", 
                    DeviceId, startAddress, quantity);

                if (_transport is ModbusTcpTransport tcpTransport)
                {
                    return await tcpTransport.ReadCoilsAsync(startAddress, quantity, timeout);
                }
                else if (_transport is ModbusRtuTransport rtuTransport)
                {
                    return await rtuTransport.ReadCoilsAsync(startAddress, quantity, timeout);
                }
                else
                {
                    // 使用通用协议方式
                    var parameters = new Dictionary<string, object>
                    {
                        ["StartAddress"] = startAddress,
                        ["Quantity"] = quantity
                    };

                    var commandData = await _protocol.BuildCommandAsync("READ_COILS", parameters);
                    var response = await _transport.SendAndReceiveAsync(commandData, timeout);

                    if (response.Success && response.Data != null)
                    {
                        var deviceData = await _protocol.ParseDeviceDataAsync(response.Data);
                        if (deviceData != null && deviceData.DataValues.ContainsKey("Coils"))
                        {
                            var coils = (bool[])deviceData.DataValues["Coils"];
                            return CommunicationResult<bool[]>.CreateSuccess(coils, "读取线圈状态成功");
                        }
                    }

                    return CommunicationResult<bool[]>.CreateFailure(response.Message, response.ErrorCode, response.Exception);
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "读取线圈状态时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult<bool[]>.CreateFailure($"读取线圈状态异常: {ex.Message}", "ReadCoilsException", ex);
            }
        }

        /// <summary>
        /// 读取保持寄存器
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="quantity">数量</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>寄存器值</returns>
        public async Task<CommunicationResult<ushort[]>> ReadHoldingRegistersAsync(ushort startAddress, ushort quantity, int timeout = 5000)
        {
            try
            {
                _logger?.LogDebug("读取保持寄存器，设备ID: {DeviceId}，起始地址: {StartAddress}，数量: {Quantity}", 
                    DeviceId, startAddress, quantity);

                if (_transport is ModbusTcpTransport tcpTransport)
                {
                    return await tcpTransport.ReadHoldingRegistersAsync(startAddress, quantity, timeout);
                }
                else if (_transport is ModbusRtuTransport rtuTransport)
                {
                    return await rtuTransport.ReadHoldingRegistersAsync(startAddress, quantity, timeout);
                }
                else
                {
                    // 使用通用协议方式
                    var parameters = new Dictionary<string, object>
                    {
                        ["StartAddress"] = startAddress,
                        ["Quantity"] = quantity
                    };

                    var commandData = await _protocol.BuildCommandAsync("READ_HOLDING_REGISTERS", parameters);
                    var response = await _transport.SendAndReceiveAsync(commandData, timeout);

                    if (response.Success && response.Data != null)
                    {
                        var deviceData = await _protocol.ParseDeviceDataAsync(response.Data);
                        if (deviceData != null && deviceData.DataValues.ContainsKey("Registers"))
                        {
                            var registers = (ushort[])deviceData.DataValues["Registers"];
                            return CommunicationResult<ushort[]>.CreateSuccess(registers, "读取保持寄存器成功");
                        }
                    }

                    return CommunicationResult<ushort[]>.CreateFailure(response.Message, response.ErrorCode, response.Exception);
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "读取保持寄存器时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult<ushort[]>.CreateFailure($"读取保持寄存器异常: {ex.Message}", "ReadHoldingRegistersException", ex);
            }
        }

        /// <summary>
        /// 写单个线圈
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>写入结果</returns>
        public async Task<CommunicationResult> WriteSingleCoilAsync(ushort address, bool value, int timeout = 5000)
        {
            try
            {
                _logger?.LogDebug("写单个线圈，设备ID: {DeviceId}，地址: {Address}，值: {Value}", DeviceId, address, value);

                if (_transport is ModbusTcpTransport tcpTransport)
                {
                    return await tcpTransport.WriteSingleCoilAsync(address, value, timeout);
                }
                else if (_transport is ModbusRtuTransport rtuTransport)
                {
                    return await rtuTransport.WriteSingleCoilAsync(address, value, timeout);
                }
                else
                {
                    // 使用通用协议方式
                    var parameters = new Dictionary<string, object>
                    {
                        ["Address"] = address,
                        ["Value"] = value
                    };

                    var commandData = await _protocol.BuildCommandAsync("WRITE_SINGLE_COIL", parameters);
                    var response = await _transport.SendAndReceiveAsync(commandData, timeout);

                    return new CommunicationResult
                    {
                        Success = response.Success,
                        Message = response.Success ? "写单个线圈成功" : response.Message,
                        ErrorCode = response.ErrorCode,
                        Exception = response.Exception
                    };
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "写单个线圈时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult.CreateFailure($"写单个线圈异常: {ex.Message}", "WriteSingleCoilException", ex);
            }
        }

        /// <summary>
        /// 写单个寄存器
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>写入结果</returns>
        public async Task<CommunicationResult> WriteSingleRegisterAsync(ushort address, ushort value, int timeout = 5000)
        {
            try
            {
                _logger?.LogDebug("写单个寄存器，设备ID: {DeviceId}，地址: {Address}，值: {Value}", DeviceId, address, value);

                if (_transport is ModbusTcpTransport tcpTransport)
                {
                    return await tcpTransport.WriteSingleRegisterAsync(address, value, timeout);
                }
                else if (_transport is ModbusRtuTransport rtuTransport)
                {
                    return await rtuTransport.WriteSingleRegisterAsync(address, value, timeout);
                }
                else
                {
                    // 使用通用协议方式
                    var parameters = new Dictionary<string, object>
                    {
                        ["Address"] = address,
                        ["Value"] = value
                    };

                    var commandData = await _protocol.BuildCommandAsync("WRITE_SINGLE_REGISTER", parameters);
                    var response = await _transport.SendAndReceiveAsync(commandData, timeout);

                    return new CommunicationResult
                    {
                        Success = response.Success,
                        Message = response.Success ? "写单个寄存器成功" : response.Message,
                        ErrorCode = response.ErrorCode,
                        Exception = response.Exception
                    };
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "写单个寄存器时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult.CreateFailure($"写单个寄存器异常: {ex.Message}", "WriteSingleRegisterException", ex);
            }
        }

        /// <summary>
        /// 发送自定义命令
        /// </summary>
        /// <param name="command">命令</param>
        /// <param name="parameters">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>执行结果</returns>
        public async Task<CommunicationResult<DeviceDataModel?>> SendCustomCommandAsync(string command, 
            Dictionary<string, object>? parameters = null, int timeout = 5000)
        {
            try
            {
                _logger?.LogDebug("发送自定义命令，设备ID: {DeviceId}，命令: {Command}", DeviceId, command);

                var commandData = await _protocol.BuildCommandAsync(command, parameters);
                var response = await _transport.SendAndReceiveAsync(commandData, timeout);

                if (response.Success && response.Data != null)
                {
                    var deviceData = await _protocol.ParseDeviceDataAsync(response.Data);
                    return CommunicationResult<DeviceDataModel?>.CreateSuccess(deviceData, "自定义命令执行成功");
                }

                return CommunicationResult<DeviceDataModel?>.CreateFailure(response.Message, response.ErrorCode, response.Exception);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "发送自定义命令时发生异常，设备ID: {DeviceId}，命令: {Command}", DeviceId, command);
                return CommunicationResult<DeviceDataModel?>.CreateFailure($"发送自定义命令异常: {ex.Message}", "CustomCommandException", ex);
            }
        }

        /// <summary>
        /// 获取设备状态
        /// </summary>
        /// <returns>设备状态</returns>
        public DeviceStatus GetDeviceStatus()
        {
            return new DeviceStatus
            {
                DeviceId = DeviceId,
                DeviceName = DeviceName,
                IsConnected = IsConnected,
                ConnectionInfo = ConnectionInfo,
                LastUpdateTime = DateTime.Now,
                Status = IsConnected ? "Online" : "Offline",
                ProtocolName = _protocol.ProtocolName,
                ProtocolVersion = _protocol.Version,
                TransportType = _transport.TransportType
            };
        }

        /// <summary>
        /// 配置传输参数
        /// </summary>
        /// <param name="parameters">参数</param>
        /// <returns>配置结果</returns>
        public async Task<CommunicationResult> ConfigureTransportAsync(Dictionary<string, object> parameters)
        {
            try
            {
                _logger?.LogDebug("配置传输参数，设备ID: {DeviceId}", DeviceId);
                return await _transport.ConfigureAsync(parameters);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "配置传输参数时发生异常，设备ID: {DeviceId}", DeviceId);
                return CommunicationResult.CreateFailure($"配置传输参数异常: {ex.Message}", "ConfigurationException", ex);
            }
        }

        #region 事件处理

        /// <summary>
        /// 处理传输层数据接收事件
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="data">接收到的数据</param>
        private async void OnTransportDataReceived(object? sender, byte[] data)
        {
            try
            {
                _logger?.LogDebug("接收到传输层数据，设备ID: {DeviceId}，数据长度: {Length}", DeviceId, data.Length);

                var deviceData = await _protocol.ParseDeviceDataAsync(data);
                if (deviceData != null)
                {
                    deviceData.DeviceId = DeviceId;
                    deviceData.DeviceName = DeviceName;
                    deviceData.TransportType = _transport.TransportType;
                    deviceData.DataSource = ConnectionInfo;

                    _logger?.LogDebug("设备数据解析成功，设备ID: {DeviceId}，数据类型: {DataType}", DeviceId, deviceData.DataType);

                    DataReceived?.Invoke(this, deviceData);
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "处理传输层数据接收事件时发生异常，设备ID: {DeviceId}", DeviceId);
            }
        }

        /// <summary>
        /// 处理传输层连接状态变化事件
        /// </summary>
        /// <param name="sender">发送者</param>
        /// <param name="isConnected">连接状态</param>
        private void OnTransportConnectionStatusChanged(object? sender, bool isConnected)
        {
            try
            {
                _logger?.LogInformation("传输层连接状态变化，设备ID: {DeviceId}，状态: {Status}", 
                    DeviceId, isConnected ? "已连接" : "已断开");

                ConnectionStatusChanged?.Invoke(this, isConnected);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "处理传输层连接状态变化事件时发生异常，设备ID: {DeviceId}", DeviceId);
            }
        }

        #endregion

        #region IDisposable实现

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (_disposed) return;

            try
            {
                _logger?.LogInformation("开始释放Modbus设备资源，设备ID: {DeviceId}", DeviceId);

                // 取消事件订阅
                _transport.DataReceived -= OnTransportDataReceived;
                _transport.ConnectionStatusChanged -= OnTransportConnectionStatusChanged;

                // 断开连接
                if (IsConnected)
                {
                    _ = Task.Run(async () =>
                    {
                        try
                        {
                            await DisconnectAsync();
                        }
                        catch (Exception ex)
                        {
                            _logger?.LogError(ex, "释放资源时断开连接失败，设备ID: {DeviceId}", DeviceId);
                        }
                    });
                }

                // 释放传输层资源
                _transport?.Dispose();

                _disposed = true;
                _logger?.LogInformation("Modbus设备资源释放完成，设备ID: {DeviceId}", DeviceId);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "释放Modbus设备资源时发生异常，设备ID: {DeviceId}", DeviceId);
            }
        }

        #endregion
    }
}